; clangers on the dancefloor
; by Gasman / Hooy-Program

align		macro n
			org ($ + n - 1) / n * n
			endm
			
			org 0x8000
			
			include "make_sine.asm"
			
			; Build x-coordinate table.
			; plan: take calculated intervals: (height-7.5).step(height-0.5,1) do |y|
			; puts p*height*8192/y
			; = 244,193,160,136,119,105,94,86
			; put in bc with top 3 bits shifted into b
			; loop+add 32 times. subtract bc*16 from hl=0x8000
			; to give the starting point: or, in other words hl=0x8000-tbl[y]<<7

			ld hl,perspect_x
			ld de,0x8100
calc_px_lp
			ld b,(hl)
			ld c,0
			srl b	; if we need to scrounge 4 bytes from somewhere at the expense of
			rr c	; accuracy, remove these and preshift perspect_x right one bit instead
			inc hl
			push hl
			ld hl,0x8000
			sbc hl,bc

			ld a,4
shiftlp
			srl b
			rr c
			dec a
			jr nz,shiftlp
			
fill_px_lp
			ld a,h
			ld (de),a
			add hl,bc
			inc e
			jr z,done_px
			ld a,e
			and 0x1f
			jr nz,fill_px_lp
			pop hl
			jr calc_px_lp
done_px		
			pop hl

			; hl now points to perspect_y
			; replicate perspect_y over page 0x8200
			inc d		; = ld de,0x8200
fill_py_1
			ld a,(hl)
			inc hl
			ld b,32
fill_py_lp
			ld (de),a
			inc e
			jr z,done_fill_py
			djnz fill_py_lp
			jr fill_py_1
done_fill_py
			
			
			; set up AY
			ld bc,0xfffd
			ld de,0xffbf
			ld a,7
			out (c),a
			ld b,e
			ld a,0xf8
			out (c),a
			ld b,d
			ld a,1
			out (c),a
			ld b,e
			out (c),a
						
discolp
			exx		; keep the above bc/de values handy
			halt
			
sine_pos	ld hl,bigsine
			inc l
			ld (sine_pos+1),hl
			push hl
			ld e,(hl)
			ld bc,ksintheta
			call mkmultable		; build a multiple-of-sines table
			pop hl

			; now do the same for cosine
			ld a,l
			add a,64
			ld l,a
			ld e,(hl)
			inc b
			call mkmultable
			
			ld bc,0x5a00
			ld hl,perspect
project_lp
			push hl
			push bc
			ld e,(hl)	; get floor X coordinate
			inc h
			ld d,(hl)	; get floor Y coordinate
			inc h
			ld l,d
			ld a,(hl)	; get y*sin(t)
			inc h
			ld l,e		; get x*cos(t)
			add a,(hl)
			ld b,a

			ld l,d		; get y*cos(t)
			ld a,(hl)
			dec h
			ld l,e		; get x*sin(t)
			sub(hl)
			
			xor b
			rrca
			; srl a		; use this instead of rrca to remove BRIGHT noise
			srl a

			pop bc

			ld (bc),a
			pop hl
			inc l
			inc c
			jr nz,project_lp
			
			; do music
			exx
			
			ld b,d
			xor a
			out (c),a
			ld b,e
			ld a,(0x847f)	; returns the current cos(theta)/2
			add a,128
			out (c),a
			
			ld b,d
			ld a,8		; set volume of channel A
			out (c),a
			ld b,e
			
			ld hl,byte_0x02
			rlc (hl)
			jr nc,no_play_note

			; this would have been a really clever way of saving a byte, by re-using a spare
			; 0x25 elsewhere in the code.
			; In the end I might as well have just done foo:ld a,0x25 / rlca / ld (foo+1),a
			; which is the same amount of bytes. What the hell
			ld hl,byte_0x25
			rlc (hl)
			ld a,(hl)
;			sbc a,a		; bollocks to the sensible code... ld a,(hl) sounds nicer
;			and (hl)
;			and 0x0f
			
			out (c),a

no_play_note
			jr discolp

; make a table consisting of multiples of the signed value in e	
mkmultable
			; first sign-extend de
			sla e
			sbc a,a
			ld d,a
			; now fill the table
			ld hl,0
mkmultable_lp
			ld a,h
			ld (bc),a
			add hl,de
			inc c
			jr nz,mkmultable_lp
			ret

			; intervals between texture x coords:
			; (height-7.5).step(height-0.5,1) do |y|
			;   puts p*height*8192/y
perspect_x	db 244,193,160,136,119,105,94,86

			; texture y coords for each screen byte,
			; calculated as k*(1-q)/(q*(1-k)) where
			; q = y/height, y = (height-7.5 .. height-0.5),
			; height = 11.3, p = 0.01, k = 0.2
			; - for table lookups to work, need to be replicated
			; across page 0x8200 such that each number repeats 32 times
perspect_y	db 126,86,60,42,28,18,9
byte_0x02	db 2		; yoink - we'll steal that bit for our music tempo timer

perspect	equ 0x8100
ksintheta	equ 0x8300
kcostheta	equ 0x8400
bigsine		equ 0x8500